
#include "stdafx.h"
#include "client_simulator.hpp"
boost::tribool response_parser::consume(response_message& rep, char input)
{
    switch (state_)
    {
    case version_h:
        if (!is_char(input) || is_ctl(input) || is_tspecial(input))
        {
            return false;
        }
        else if (input == 'H')
        {
            state_ = version_t_1;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_t_1:
        if (input == 'T')
        {
            state_ = version_t_2;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_t_2:
        if (input == 'T')
        {
            state_ = version_p;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_p:
        if (input == 'P')
        {
            state_ = version_slash;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_slash:
        if (input == '/')
        {
            rep.version_major = 0;
            rep.version_minor = 0;
            state_ = version_major_start;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_major_start:
        if (is_digit(input))
        {
            rep.version_major = rep.version_major * 10 + input - '0';
            state_ = version_major;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_major:
        if (input == '.')
        {
            state_ = version_minor_start;
            return boost::indeterminate;
        }
        else if (is_digit(input))
        {
            rep.version_major = rep.version_major * 10 + input - '0';
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_minor_start:
        if (is_digit(input))
        {
            rep.version_minor = rep.version_minor * 10 + input - '0';
            state_ = version_minor;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case version_minor:
        if (input == ' ')
        {
            state_ = status_code_start;
            return boost::indeterminate;
        }
        else if (is_digit(input))
        {
            rep.version_minor = rep.version_minor * 10 + input - '0';
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case status_code_start:
        if (is_digit(input))
        {
            rep.status_code = rep.status_code * 10 + input - '0';
            state_ = status_code;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case status_code:
        if (input == ' ')
        {
            state_ = status_message_start;
            return boost::indeterminate;
        }
        else if (is_digit(input))
        {
            rep.status_code = rep.status_code * 10 + input - '0';
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case status_message_start:
        if (!is_char(input) || is_ctl(input) || is_tspecial(input))
        {
            return false;
        }
        else
        {
            state_ = status_message;
            rep.status_message.push_back(input);
            return boost::indeterminate;
        }

    case status_message:
        if (input == '\r')
        {
            state_ = expecting_newline_1;
            return boost::indeterminate;
        }
        else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
        {
            return false;
        }
        else
        {
            rep.status_message.push_back(input);
            return boost::indeterminate;
        }

    case expecting_newline_1:
        if (input == '\n')
        {
            state_ = header_line_start;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case header_line_start:
        if (input == '\r')
        {
            state_ = expecting_newline_3;
            return boost::indeterminate;
        }
        else if (!rep.headers.empty() && (input == ' ' || input == '\t'))
        {
            state_ = header_lws;
            return boost::indeterminate;
        }
        else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
        {
            return false;
        }
        else
        {
            rep.headers.push_back(h_key_value());
            rep.headers.back().name.push_back(input);
            state_ = header_name;
            return boost::indeterminate;
        }

    case header_lws:
        if (input == '\r')
        {
            state_ = expecting_newline_2;
            return boost::indeterminate;
        }
        else if (input == ' ' || input == '\t')
        {
            return boost::indeterminate;
        }
        else if (is_ctl(input))
        {
            return false;
        }
        else
        {
            state_ = header_value;
            rep.headers.back().value.push_back(input);
            return boost::indeterminate;
        }

    case header_name:
        if (input == ':')
        {
            boost::to_lower(rep.headers.back().name);
            state_ = header_value;
            return boost::indeterminate;
        }
        else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
        {
            return false;
        }
        else
        {
            rep.headers.back().name.push_back(input);
            return boost::indeterminate;
        }

    case space_before_header_value:
        if (input == ' ')
        {
            state_ = header_value;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case header_value:
        if (input == '\r')
        {
            state_ = expecting_newline_2;
            return boost::indeterminate;
        }
        else if (is_ctl(input))
        {
            return false;
        }
        else
        {
            rep.headers.back().value.push_back(input);
            return boost::indeterminate;
        }

    case expecting_newline_2:
        if (input == '\n')
        {
            if (rep.headers.size() > 0)
            {
                boost::trim(rep.headers.back().value);
            }
            state_ = header_line_start;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case expecting_newline_3:
        if (input == '\n')
        {
            t_vt_hk_value::iterator it =
                std::find_if(
                rep.headers.begin(),
                rep.headers.end(),
                boost::bind(&h_key_value::name, _1) == "content-length");
            if (it == rep.headers.end())
            {
                return false;
            }

            content_size_ = atoi(it->value.c_str());

            if (content_size_ <= 0 || content_size_ > RECV_BUF_LEN)
            {
                return false;
            }
            rep.content.clear();
            rep.content.reserve(content_size_);

            state_ = content;
            return boost::indeterminate;
        }
        else
        {
            return false;
        }

    case content:
        if (rep.content.size() < static_cast<size_t>(content_size_))
        {
            rep.content.push_back(input);
            if (rep.content.size() == static_cast<size_t>(content_size_))
            {
                reset();
                return true;
            }
            else
            {
                return boost::indeterminate;
            }
        }
        else
        {
            return false;
        }

    default:
        return false;
    }
}
